Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: explicit EVM call stack #136

Merged

Conversation

birchmd
Copy link
Contributor

@birchmd birchmd commented Oct 26, 2022

In the current design, the EVM call stack is emulated via the Rust call stack (using recursive calls to call_inner and create_inner). However, this creates an incompatibility with the EVM spec when the Rust call stack can overflow before the EVM call stack limit. Indeed, we have observed this in Aurora.

In this PR, I use the interrupt mechanism already part of the runtime's design to enable an explicit EVM call stack data structure, and resolve all subcalls in an EVM transaction within one loop instead of recursive Rust function calls. This resolves the stack overflow issue.

Copy link
Contributor

@nanocryk nanocryk left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

Ok(()) => {
let mut value = H256::default();
U256::one().to_big_endian(&mut value[..]);
runtime.machine.stack_mut().push(value)?;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why no keep using push_u256! and push! macros?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The push* macros return the Control structure, whereas in this function I want to return the ExitReason directly.

}
}

impl<'a, 'config> Drop for ResolveCreate<'a, 'config> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If Drop is no longer useful, we can probably get rid of ResolveCreate and ResolveCall entirely?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably they can be removed entirely, yes. I think it should be done as a follow-up PR to keep the diff on this PR minimal.

@@ -1269,7 +1392,18 @@ impl<'inner, 'config, 'precompiles, S: StackState<'config>, P: PrecompileSet> Pr
context.clone(),
) {
Capture::Exit((s, v)) => (s, v),
Capture::Trap(_) => unreachable!("Trap is infaillible since StackExecutor is sync"),
Capture::Trap(rt) => {
// Ideally this would pass the interrupt back to the executor so it could be
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would require that precompiles also trap and be resumed later, which would make them hard to write without using (currently unstable) generators.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think generators are necessary, but I do agree it makes the precompiles interface much more complex is if it returns a Capture type. If we end up changing it then I think it should be done as a separate PR, and in that PR ergonomics of precompiles can be carefully considered.

@crystalin
Copy link
Contributor

@sorpaas what do you think about it ?

Copy link
Member

@sorpaas sorpaas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry about the delay. Overall LGTM. Currently just a grumble.

runtime/src/lib.rs Outdated Show resolved Hide resolved
@birchmd
Copy link
Contributor Author

birchmd commented Dec 16, 2022

Thanks for the review @sorpaas

I've fixed the typo you pointed out. I also pushed a fix where some tracing events were missing for EVM calls that executed in the new explicit call stack. And I rebased on master since the PR was pretty old.

Please take another look and let me know if you have any other comments.

@sorpaas sorpaas merged commit 842e03d into rust-ethereum:master Dec 19, 2022
@mrLSD mrLSD deleted the upstream-fix-stackoverflow branch December 6, 2023 19:57
zjb0807 added a commit to AcalaNetwork/Acala that referenced this pull request Jan 22, 2024
zjb0807 added a commit to AcalaNetwork/Acala that referenced this pull request Jan 29, 2024
* update PrecompileHandle ref: rust-ethereum/evm#122

* update fee calculation ref: rust-ethereum/evm#132

* add code_size/code_hash fn in StackState trait ref: rust-ethereum/evm#140

* update evm call stack ref: rust-ethereum/evm#136

* update evm call stack ref: rust-ethereum/evm#155

* add shanghai eips 3651, 3855, 3860 ref: rust-ethereum/evm#152

* update is_precompile ref: rust-ethereum/evm#157

* fix eip-3860 ref: rust-ethereum/evm#160

* update runtime config ref: rust-ethereum/evm#161

* add eip-4399 ref: rust-ethereum/evm#162

* fix eip-2618 ref: rust-ethereum/evm#163

* fix nonce back to U256 ref: rust-ethereum/evm#166

* remove exit_substate in create functions ref: rust-ethereum/evm#168

* record external cost ref: rust-ethereum/evm#170

* add record_external_operation ref: rust-ethereum/evm#171

* add storage_growth ref: rust-ethereum/evm#173

* update evm

* switch to shanghai hardfork

* update ecrecover ref: polkadot-evm/frontier#964 (#2696)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants